﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpJoinUtils.h"
#include "IDocument.h"
#include "JoinUtils.h"
#include "IElementPositionPoints.h"
#include "IInstance.h"
#include "IElementModelShape.h"
#include "Vector3dUtils.h"
#include "IGraphicsBRepFace.h"
#include "AlgorithmPositionJudge.h"
#include "IGraphicsPlane.h"
#include "ICurve3dSurfaceIntersection.h"
#include "NotificationUtils.h"
#include "IStructureInstanceJoinBehavior.h"
#include "IElementBasicInformation.h"
#include "IRegenerator.h"
#include "UniIdentity.h"
#include "IGraphicsElementShape.h"
#include "GraphicsNodeUtils.h"
#include "JoinCutInstanceUtils.h"

#include "GbmpGraphicsNodeUtils.h"
#include "GbmpCutUtils.h"
#include "GbmpColumnUtils.h"
#include "GbmpWallUtils.h"
#include "GbmpBeamUtils.h"
#include "GbmpStripFoundationUtils.h"
#include "GbmpJoinConditionUtils.h"
#include "GbmpJoinCutInstanceUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

// 暂时处理JoinUtil废弃警告，后续JoinUtil私有化后把这里恢复

bool GbmpJoinUtils::CreateWallWallJoins(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, bool tryPassiveJoin)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   if (!GbmpWallUtils::IsJoinable(pAttachingInstance))
      return false;

   std::vector<IInstance*> pAttachedInstances = GetAttachedInstances(pDoc, pAttachingInstance, GbmpWallUtils::IsJoinable);
   bool bSucceed = CreateJoinsByJoinPosition(pAttachingInstance, JoinPosition::Start, pAttachedInstances);
   bSucceed |= CreateJoinsByJoinPosition(pAttachingInstance, JoinPosition::End, pAttachedInstances);

   if (tryPassiveJoin)
   {
      FOR_EACH(pAttachedInstance, pAttachedInstances)
      {
         bSucceed |= CreateTTypeJoins(pAttachedInstance, pAttachingInstance);
      }
   }

   return bSucceed;
}

bool GbmpJoinUtils::DoLTypeJoin(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, gcmp::JoinPosition attachingJoinEnd, IInstance* pAttachedInstance, bool isRepairModel)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachedInstance, L"无效pAttachedInstance",L"GDMPLab",L"2024-03-30");

   IElementPositionPoints* pCtrlPtBehavior = pAttachingInstance->GetPositionPoints();
   Vector3d ptAttachingEndPoint = pCtrlPtBehavior ? pCtrlPtBehavior->GetControlPoint((int32_t)attachingJoinEnd) : Vector3d::Zero;
   JoinPosition attachedJoinEnd = GetClosestEndPointJoinPosition(pAttachedInstance, ptAttachingEndPoint);
   if (ElementJoinUtils::HasElementJoinByJoinPosition(pAttachedInstance, attachedJoinEnd))
      return false;

   //模型修复操作时，梁连接是按截面面积大的作为主（延伸对象）
   if (isRepairModel)
   {
      return CreateLTypeJionBySectionalAreaPriority(pDoc, pAttachingInstance, attachingJoinEnd, pAttachedInstance, attachedJoinEnd) != nullptr;
   }

   return CreateLTypeJion(pDoc, pAttachingInstance, attachingJoinEnd, pAttachedInstance, attachedJoinEnd) != nullptr;
}

gcmp::IElementJoin* GbmpJoinUtils::CreateLTypeJionBySectionalAreaPriority(gcmp::IDocument* pDoc, IInstance* pAttachingInstance, JoinPosition attachingPos, IInstance* pAttachedInstance, JoinPosition attachedPos)
{
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachingInstance, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachedInstance, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   if (GbmpBeamUtils::IsBeam(pAttachingInstance) && GbmpBeamUtils::IsBeam(pAttachedInstance))
   {
      //连接目前只支持标准梁，不支持自定义截面，变截面梁和T形梁连接
      double sectionalArea1 = GbmpBeamUtils::GetBeamWidth(pAttachingInstance) * GbmpBeamUtils::GetBeamHeight(pAttachingInstance);
      double sectionalArea2 = GbmpBeamUtils::GetBeamWidth(pAttachedInstance) * GbmpBeamUtils::GetBeamHeight(pAttachedInstance);

      //梁连接时，截面面积大的做为主对象（attached对象，需要延伸的对象）
      if (MathUtils::IsGreaterThan(sectionalArea1, sectionalArea2, Constants::DOUBLE_EPS))
      {
         return CreateLTypeJion(pDoc, pAttachedInstance, attachedPos, pAttachingInstance, attachingPos);
      }
   }

   return CreateLTypeJion(pDoc, pAttachingInstance, attachingPos, pAttachedInstance, attachedPos);
}

IElementJoin* GbmpJoinUtils::CreateLTypeJion(gcmp::IDocument* pDoc, IInstance* pAttachingInstance, JoinPosition attachingPos, IInstance* pAttachedInstance, JoinPosition attachedPos)
{
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachingInstance, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachedInstance, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   if (GbmpJoinConditionUtils::HasJoinOnEnd(pDoc, pAttachingInstance->GetElementId(), attachingPos, pAttachedInstance->GetElementId(), attachedPos))
   {
      return nullptr;
   }

   JoinData joinData(pAttachingInstance->GetBasicInformation()->GetElementId(), attachingPos, pAttachedInstance->GetBasicInformation()->GetElementId(), attachedPos);
   GetJoinData(pAttachingInstance, attachingPos, pAttachedInstance, attachedPos, JoinType::Abut, joinData); //判断优先级

   if (GbmpJoinConditionUtils::IsSatisfyLTypeJoin(pDoc, joinData.AttachingElementId, joinData.AttachingPosition, joinData.AttachedElementId, joinData.AttachedPosition))
   {
      return IElementJoin::Create(IStructureInstanceJoinBehavior::CreateInstanceJoinBehavior(pDoc, JoinType::Abut), joinData);
   }
   else if (GbmpJoinConditionUtils::IsSatisfyLTypeJoin(pDoc, joinData.AttachedElementId, joinData.AttachedPosition, joinData.AttachingElementId, joinData.AttachingPosition)) //遇到小短墙不能连接时，尝试Attaching和Attached关系进行再次连接
   {
      return IElementJoin::Create(IStructureInstanceJoinBehavior::CreateInstanceJoinBehavior(pDoc, JoinType::Abut), joinData);
   }

   return nullptr;
}

bool GbmpJoinUtils::CreateJoinsByJoinPosition(gcmp::IInstance* pAttachingInstance, gcmp::JoinPosition attachingJoinPosition, const std::vector<gcmp::IInstance*>& pAttachedInstances)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   gcmp::IDocument* pDoc = pAttachingInstance->GetDocument();
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");

   if (ElementJoinUtils::HasElementJoinByJoinPosition(pAttachingInstance, attachingJoinPosition))
      return false;

   bool createJoinSucceed = false;
   FOR_EACH(pAttachedInstance, pAttachedInstances)
   {
      DBG_WARN_AND_CONTINUE_UNLESS(pAttachedInstance, L"pAttachedInstance为空!",L"GDMPLab",L"2024-03-30");
      if (pAttachedInstance == pAttachingInstance)
         continue;

      //(1) 尝试与最近端点接(主动)
      createJoinSucceed = DoLTypeJoin(pDoc, pAttachingInstance, attachingJoinPosition, pAttachedInstance);

      //(2) 尝试T接(主动)
      if (!createJoinSucceed && GbmpJoinConditionUtils::AdjustInstancePointForTTypeJoin(pAttachingInstance, attachingJoinPosition, pAttachedInstance))
      {
         JoinData joinData(pAttachingInstance->GetBasicInformation()->GetElementId(), attachingJoinPosition,
            pAttachedInstance->GetBasicInformation()->GetElementId(), JoinPosition::Middle);
         createJoinSucceed = IElementJoin::Create(IStructureInstanceJoinBehavior::CreateInstanceJoinBehavior(pDoc, JoinType::TType), joinData) != nullptr;
      }

      //端点处只允许一个连接
      if (createJoinSucceed)
         break;
   }

   return createJoinSucceed;
}

bool GbmpJoinUtils::CreateTTypeJoins(IInstance* pAttachingInstance, IInstance* pAttachedInstance)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"pAttachingInstance为空!",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachedInstance, L"pAttachedInstance为空!",L"GDMPLab",L"2024-03-30");
   if (pAttachingInstance == pAttachedInstance)
      return false;

   if (!GbmpJoinConditionUtils::AreInstancesHaveVerticalOverlap(pAttachingInstance, pAttachedInstance))
      return false;

   IDocument* pDoc = pAttachedInstance->GetDocument();
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空!",L"GDMPLab",L"2024-03-30");

   bool createJoinSucceed = false;
   JoinPosition attachingJoinEndPositions[] = { JoinPosition::Start, JoinPosition::End };

   //两端都可以建立T形连接关系，例：弧墙
   FOR_EACH(attachingJoinPosition, attachingJoinEndPositions)
   {
      if (ElementJoinUtils::HasElementJoinByJoinPosition(pAttachingInstance, attachingJoinPosition))
         continue;

      if (GbmpJoinConditionUtils::AdjustInstancePointForTTypeJoin(pAttachingInstance, attachingJoinPosition, pAttachedInstance))
      {
         JoinData joinData(pAttachingInstance->GetBasicInformation()->GetElementId(), attachingJoinPosition,
            pAttachedInstance->GetBasicInformation()->GetElementId(), JoinPosition::Middle);
         createJoinSucceed = IElementJoin::Create(IStructureInstanceJoinBehavior::CreateInstanceJoinBehavior(pDoc, JoinType::TType), joinData) != nullptr;
      }
   }

   return createJoinSucceed;
}

std::vector<gcmp::IInstance*> GbmpJoinUtils::GetAttachedInstances(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, IsAllowJoinFunction isAllowJoinFunc, const std::set<ElementId>& targetInstances)
{
   std::vector<IInstance*> instances;
   DBG_WARN_AND_RETURN_UNLESS(pDoc, instances, L"pDoc为空",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_UNLESS(pAttachingInstance, instances, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_UNLESS(pAttachingInstance->GetElementModelShape(), instances, L"无效pElementShapeBehavior",L"GDMPLab",L"2024-03-30");
   const IGraphicsElementShape* pGRep = pAttachingInstance->GetElementModelShape()->GetGraphicsElementShape();
   DBG_WARN_AND_RETURN_UNLESS(pGRep, instances, L"无效pGRep",L"GDMPLab",L"2024-03-30");
   Box3d box = pGRep->GetBox();
   double width = GbmpJoinCutInstanceUtils::GetWidth(pAttachingInstance);
   box = GbmpGraphicsNodeUtils::ExpandBox3dExceptZValue(box, width / 3);
   std::vector<ElementId> outputElementIds;
   if (GraphicsNodeUtils::GetElementIdsInBox(pDoc, box, outputElementIds))
   {
      FOR_EACH(id, outputElementIds)
      {
         gcmp::IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(id));
         if (pInstance != nullptr)
         {
            if (pInstance != pAttachingInstance && isAllowJoinFunc(pInstance))
            {
               if (targetInstances.empty() || targetInstances.find(pInstance->GetBasicInformation()->GetElementId()) != targetInstances.end())
                  instances.push_back(pInstance);
            }
         }
      }
   }

   return instances;
}

bool GbmpJoinUtils::CreateBeamBeamJoins(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingBeam, bool tryPassiveJoin)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingBeam, L"无效pAttachingBeam",L"GDMPLab",L"2024-03-30");
   if (!GbmpBeamUtils::IsJoinable(pAttachingBeam))
      return false;

   std::vector<IInstance*> pAttachedInstances = GetAttachedInstances(pDoc, pAttachingBeam, GbmpBeamUtils::IsJoinable);
   bool bSucceed = CreateJoinsByJoinPosition(pAttachingBeam, JoinPosition::Start, pAttachedInstances);
   bSucceed |= CreateJoinsByJoinPosition(pAttachingBeam, JoinPosition::End, pAttachedInstances);

   if (tryPassiveJoin)
   {
      FOR_EACH(pAttachedInstance, pAttachedInstances)
      {
         bSucceed |= CreateTTypeJoins(pAttachedInstance, pAttachingBeam);
      }
   }

   return bSucceed;
}

bool GbmpJoinUtils::AdjustControlPointToInstance(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, gcmp::JoinPosition attachingJoinEnd, const std::vector<gcmp::IInstance*>& pAttachedInstances)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");

   bool res = false;
   if (ElementJoinUtils::HasElementJoinByJoinPosition(pAttachingInstance, attachingJoinEnd))
   {
      return false;
   }

   FOR_EACH(pAttachedInstance, pAttachedInstances)
   {
      DBG_WARN_AND_CONTINUE_UNLESS(pAttachedInstance, L"pAttachedInstance为空!",L"GDMPLab",L"2024-03-30");

      if (pAttachedInstance == pAttachingInstance)
         continue;

      if (!GbmpJoinCutInstanceUtils::IsJoinable(pAttachedInstance))
      {
         continue;
      }

      if (JoinUtils::AdjustControlPointToInstance(pAttachingInstance, attachingJoinEnd, pAttachedInstance))
         res = true;
   }

   return res;
}

bool GbmpJoinUtils::AdjustBeamControlPointsToInstance(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, IsAllowJoinFunction isAllowJoinFunc, const std::set<ElementId>& targetInsts)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   if (!GbmpBeamUtils::IsJoinable(pAttachingInstance))
      return false;

   std::vector<gcmp::IInstance*> pAttachedInstances = GbmpJoinUtils::GetAttachedInstances(pDoc, pAttachingInstance, isAllowJoinFunc, targetInsts);
   bool bSucceed = AdjustControlPointToInstance(pDoc, pAttachingInstance, JoinPosition::Start, pAttachedInstances);
   bSucceed |= AdjustControlPointToInstance(pDoc, pAttachingInstance, JoinPosition::End, pAttachedInstances);
   return bSucceed;
}

bool GbmpJoinUtils::AdjustControlPointOrCreateJoin(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, gcmp::JoinPosition attachingJoinEnd, const std::vector<gcmp::IInstance*>& pAttachedInstances)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");

   bool res = false;
   if (ElementJoinUtils::HasElementJoinByJoinPosition(pAttachingInstance, attachingJoinEnd))
   {
      return res;
   }


   FOR_EACH(pAttachedInstance, pAttachedInstances)
   {
      DBG_WARN_AND_CONTINUE_UNLESS(pAttachedInstance, L"pAttachedInstance为空!",L"GDMPLab",L"2024-03-30");

      if (pAttachedInstance == pAttachingInstance)
         continue;

      if (!GbmpJoinCutInstanceUtils::IsJoinable(pAttachedInstance))
      {
         continue;
      }

      if (!GbmpJoinConditionUtils::AreInstancesHaveVerticalOverlap(pAttachingInstance, pAttachedInstance))
      {
         continue;
      }

      //(1) 尝试L型连接
      if (DoLTypeJoin(pDoc, pAttachingInstance, attachingJoinEnd, pAttachedInstance, true))
      {
         res = true;
         break;
      }

      // (2) 尝试T型退让
      if (JoinUtils::AdjustControlPointToInstance(pAttachingInstance, attachingJoinEnd, pAttachedInstance))
      {
         res = true;
         continue; // 继续尝试和其他模型退让。
      }

      // (3) 尝试T型连接
      bool tTypeJoin = GbmpJoinConditionUtils::AdjustInstancePointForTTypeJoin(pAttachingInstance, attachingJoinEnd, pAttachedInstance);

      if (!tTypeJoin)
      {
         continue;
      }
      JoinData joinData(pAttachingInstance->GetBasicInformation()->GetElementId(), attachingJoinEnd,
         pAttachedInstance->GetBasicInformation()->GetElementId(), JoinPosition::Middle);
      IElementJoin* pElementJoin = IElementJoin::Create(IStructureInstanceJoinBehavior::CreateInstanceJoinBehavior(pDoc, JoinType::TType), joinData);
      if (tTypeJoin && pElementJoin)
      {
         res = true;
         break;
      }
   }

   return res;
}

bool GbmpJoinUtils::AdjustWallControlPointsOrCreateJoins(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, const std::set<ElementId>& targetInsts)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   if (!GbmpWallUtils::IsJoinable(pAttachingInstance))
      return false;

   std::vector<gcmp::IInstance*> pAttachedInstances = GbmpJoinUtils::GetAttachedInstances(pDoc, pAttachingInstance, GbmpWallUtils::IsJoinable, targetInsts);
   bool bSucceed = AdjustControlPointOrCreateJoin(pDoc, pAttachingInstance, JoinPosition::Start, pAttachedInstances);
   bSucceed |= AdjustControlPointOrCreateJoin(pDoc, pAttachingInstance, JoinPosition::End, pAttachedInstances);

   if (bSucceed)
      pAttachingInstance->GetDocument()->GetRegenerator()->RegenerateElement(pAttachingInstance->GetElementId());
   return bSucceed;
}

bool GbmpJoinUtils::AdjustBeamControlPointsOrCreateJoins(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, const std::set<ElementId>& targetInsts)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   if (!GbmpBeamUtils::IsJoinable(pAttachingInstance))
      return false;

   std::vector<gcmp::IInstance*> pAttachedInstances = GbmpJoinUtils::GetAttachedInstances(pDoc, pAttachingInstance, GbmpBeamUtils::IsJoinable, targetInsts);
   bool bSucceed = AdjustControlPointOrCreateJoin(pDoc, pAttachingInstance, JoinPosition::Start, pAttachedInstances);
   bSucceed |= AdjustControlPointOrCreateJoin(pDoc, pAttachingInstance, JoinPosition::End, pAttachedInstances);

   if (bSucceed)
      pAttachingInstance->GetDocument()->GetRegenerator()->RegenerateElement(pAttachingInstance->GetElementId());
   return bSucceed;
}

bool GbmpJoinUtils::CreateStripFoundationJoins(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingBeam)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingBeam, L"无效pAttachingBeam",L"GDMPLab",L"2024-03-30");
   if (!GbmpStripFoundationUtils::IsJoinable(pAttachingBeam))
      return false;

   std::vector<IInstance*> pAttachedInstances = GetAttachedInstances(pDoc, pAttachingBeam, GbmpStripFoundationUtils::IsJoinable);
   bool bSucceed = CreateJoinsByJoinPosition(pAttachingBeam, JoinPosition::Start, pAttachedInstances);
   bSucceed |= CreateJoinsByJoinPosition(pAttachingBeam, JoinPosition::End, pAttachedInstances);
   return bSucceed;
}


bool GbmpJoinUtils::CreateJoinsAndCuts(gcmp::IDocument* pDoc, gcmp::IInstance* pInstance)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstance, L"无效pInstance",L"GDMPLab",L"2024-03-30");

   bool bSucceed = false;
   if (GbmpWallUtils::IsWall(pInstance))
   {
      bSucceed = CreateWallWallJoins(pDoc, pInstance);
      bSucceed |= GbmpCutUtils::CreateWallColumnCutRelationshipByWall(pDoc, pInstance);
   }
   else if (GbmpColumnUtils::IsColumn(pInstance))
   {
      bSucceed = GbmpCutUtils::CreateWallColumnCutRelationshipByColumn(pDoc, pInstance);
   }
   else if (GbmpBeamUtils::IsBeam(pInstance))
   {
      bSucceed = CreateBeamBeamJoins(pDoc, pInstance);
   }
   else if (GbmpStripFoundationUtils::IsStripFoundation(pInstance))
   {
      bSucceed = CreateStripFoundationJoins(pDoc, pInstance);
   }

   return bSucceed;
}

bool GbmpJoinUtils::CreateJoinsAndCuts(gcmp::IDocument* pDoc, const gcmp::ElementId& id)
{
   gcmp::IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(id));
   if (pInstance != nullptr)
   {
      return CreateJoinsAndCuts(pDoc, pInstance);
   }

   return false;
}

IElementJoin* GbmpJoinUtils::CreateLTypeJoin(gcmp::IDocument* pDoc, const gcmp::ElementId& attachingId, const gcmp::ElementId& attachedId)
{
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(attachingId != attachedId, L"attachingId和attachedId不允许相同",L"GDMPLab",L"2024-03-30");
   gcmp::IInstance* pAttachingInstance = quick_cast<IInstance>(pDoc->GetElement(attachingId));
   gcmp::IInstance* pAttachedInstance = quick_cast<IInstance>(pDoc->GetElement(attachedId));

   return CreateLTypeJoin(pDoc, pAttachingInstance, pAttachedInstance);
}

gcmp::IElementJoin* GbmpJoinUtils::CreateLTypeJoin(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, gcmp::IInstance* pAttachedInstance)
{
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachedInstance, L"无效pAttachedInstance",L"GDMPLab",L"2024-03-30");
   if (GbmpWallUtils::IsWall(pAttachingInstance) && GbmpWallUtils::IsWall(pAttachedInstance))
   {
      if (GbmpWallUtils::IsJoinable(pAttachingInstance) && GbmpWallUtils::IsJoinable(pAttachedInstance))
      {
         std::pair<int, int> controlPointIndex = GetInstanceJoinPositionIndex(pAttachingInstance, pAttachedInstance);
         return CreateLTypeJoinByJoinPosition(pDoc, pAttachingInstance, (gcmp::JoinPosition)controlPointIndex.first, pAttachedInstance, (gcmp::JoinPosition)controlPointIndex.second);
      }
   }
   else if (GbmpBeamUtils::IsBeam(pAttachingInstance) && GbmpBeamUtils::IsBeam(pAttachedInstance))
   {
      if (GbmpBeamUtils::IsJoinable(pAttachingInstance) && GbmpBeamUtils::IsJoinable(pAttachedInstance))
      {
         std::pair<int, int> controlPointIndex = GetInstanceJoinPositionIndex(pAttachingInstance, pAttachedInstance);
         return CreateLTypeJoinByJoinPosition(pDoc, pAttachingInstance, (gcmp::JoinPosition)controlPointIndex.first, pAttachedInstance, (gcmp::JoinPosition)controlPointIndex.second);
      }
   }
   else
   {
      DBG_WARN_AND_RETURN_NULLPTR_UNLESS(false, L"不支持建立连接关系。",L"GDMPLab",L"2024-03-30");
   }

   return nullptr;
}

IElementJoin* GbmpJoinUtils::CreateLTypeJoinByJoinPosition(gcmp::IDocument* pDoc, gcmp::IInstance* pAttachingInstance, gcmp::JoinPosition attachingJoinPosition, gcmp::IInstance* pAttachedInstance, gcmp::JoinPosition attachedJoinPosition)
{
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachingInstance, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAttachedInstance, L"无效pAttachedInstance",L"GDMPLab",L"2024-03-30");
   if (!GbmpJoinCutInstanceUtils::IsJoinable(pAttachingInstance) || !GbmpJoinCutInstanceUtils::IsJoinable(pAttachedInstance))
   {
      return nullptr;
   }

   if (ElementJoinUtils::HasElementJoinByJoinPosition(pAttachingInstance, attachingJoinPosition) ||
      ElementJoinUtils::HasElementJoinByJoinPosition(pAttachedInstance, attachedJoinPosition))
   {
      return nullptr;
   }

   return CreateLTypeJion(pDoc, pAttachingInstance, attachingJoinPosition, pAttachedInstance, attachedJoinPosition);
}

void GbmpJoinUtils::CheckAndTryToReverseRelationshipOrDeleteJoin(gcmp::IDocument* pDoc, IElementJoin* pJoin)
{
   DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_VOID_UNLESS(pJoin, L"无效pJoin",L"GDMPLab",L"2024-03-30");
   IElementJoinBehavior* pElementJoinBehavior = pJoin->GetElementJoinBehavior();
   if (!pElementJoinBehavior)
      return;
   //检测不慢足几何连接时，尝试切换关系，若还是不满足几何连接，则删除连接关系
   if (!GbmpJoinConditionUtils::IsSatisfyGeometryJoin(pDoc, pJoin))
   {
      const INotification* lastNotification = NotificationUtils::GetLastNotification();
      NotificationTypes notiType = NotificationTypes::WarningNotificationType;
      std::wstring notiText = GBMP_TR(L"构件过短，连接失败！");
      NotificationUtils::PostNotification(notiType, notiText);
   }
}

bool GbmpJoinUtils::GetPriAndSecRelationship(const IInstance* pInstance, const IInstance* pOtherInstance, JoinType type, std::pair<ElementId, ElementId>& relationship)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstance && pOtherInstance, L"pInstance && pOtherInstance为空",L"GDMPLab",L"2024-03-30");
   //只允许类型相同的进行连接
   if (pInstance->GetBasicInformation()->GetCategoryUid() != pOtherInstance->GetBasicInformation()->GetCategoryUid())
   {
      return false;
   }
   ElementId elementId1 = pInstance->GetBasicInformation()->GetElementId();
   ElementId elementId2 = pOtherInstance->GetBasicInformation()->GetElementId();

   if (elementId1 == elementId2) //同一个构件不处理
   {
      return false;
   }
   if (type == JoinType::Miter) //斜接，无需考虑优先级
   {
      relationship.first = elementId1;
      relationship.second = elementId2;
      return false;
   }
   else if (type == JoinType::Abut || type == JoinType::SquareOff || type == JoinType::Cross)//平接，方接，十字形连接 （截面高度h>截面宽度b>绘制的先后顺序ID）
   {
      double height1 = GbmpJoinCutInstanceUtils::GetHeight(pInstance);
      double height2 = GbmpJoinCutInstanceUtils::GetHeight(pOtherInstance);
      if (abs(height1 - height2) > Constants::LENGTH_EPS)
      {
         relationship.first = height1 > height2 ? elementId1 : elementId2; //主
         relationship.second = height1 > height2 ? elementId2 : elementId1;  //次
         return true;
      }
      double width1 = GbmpJoinCutInstanceUtils::GetWidth(pInstance);
      double width2 = GbmpJoinCutInstanceUtils::GetWidth(pOtherInstance);
      if (abs(width1 - width2) > Constants::LENGTH_EPS)
      {
         relationship.first = width1 > width2 ? elementId1 : elementId2; //主
         relationship.second = width1 > width2 ? elementId2 : elementId1;  //次
         return true;
      }
      relationship.first = elementId1 < elementId2 ? elementId1 : elementId2; //主
      relationship.second = elementId1 < elementId2 ? elementId2 : elementId1;  //次
      return true;
   }
   else if (type == JoinType::TType)   //仅梁需处理优先级 截面高度h
   {
      if (!GbmpBeamUtils::IsBeam(pInstance))  //不是梁，不需要处理
      {
         return false;
      }
      double height1 = GbmpJoinCutInstanceUtils::GetHeight(pInstance);
      double height2 = GbmpJoinCutInstanceUtils::GetHeight(pOtherInstance);
      if (abs(height1 - height2) > Constants::LENGTH_EPS)
      {
         relationship.first = height1 > height2 ? elementId1 : elementId2; //主
         relationship.second = height1 > height2 ? elementId2 : elementId1;  //次
         return true;
      }
   }
   return false;
}

bool GbmpJoinUtils::GetJoinData(const IInstance* pInstance, JoinPosition position, const IInstance* pOtherInstance, JoinPosition otherPosition, JoinType type, JoinData& relationshipData)
{
   DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstance && pOtherInstance, L"pInstance && pOtherInstance为空",L"GDMPLab",L"2024-03-30");

   ElementId  attachingId = pInstance->GetBasicInformation()->GetElementId();
   ElementId  atachedId = pOtherInstance->GetBasicInformation()->GetElementId();
   std::pair<ElementId, ElementId> relationship(atachedId, attachingId);
   if (GetPriAndSecRelationship(pOtherInstance, pInstance, type, relationship)) //判断优先级
   {
      if (relationship.first != pOtherInstance->GetBasicInformation()->GetElementId()) //判断优先级是否更改
      {
         //更改优先级后，对应的JoinPosition也需要替换
         JoinPosition temp = position;
         position = otherPosition;
         otherPosition = temp;
      }
      relationshipData.AttachedElementId = relationship.first;
      relationshipData.AttachedPosition = otherPosition;
      relationshipData.AttachingElementId = relationship.second;
      relationshipData.AttachingPosition = position;
      return true;
   }
   return false;
}

gcmp::JoinPosition GbmpJoinUtils::GetClosestEndPointJoinPosition(gcmp::IInstance* pInstance, const gcmp::Vector3d& ptPoint)
{
   gcmp::JoinPosition res = JoinPosition::Invalid;
   DBG_WARN_AND_RETURN_UNLESS(pInstance, res, L"无效pInstance",L"GDMPLab",L"2024-03-30");

   const gcmp::IInstance* pConstInstance = pInstance;
   const IElementPositionPoints* pCtrlPtBehavior = pConstInstance->GetPositionPoints();
   DBG_WARN_AND_RETURN_UNLESS(pCtrlPtBehavior && pCtrlPtBehavior->GetControlPointCount() >= 2, res, L"不支持此类型，控制点不能少于2个。",L"GDMPLab",L"2024-03-30");

   Vector3d ptStart = JoinCutInstanceUtils::GetStartPoint(pInstance);
   Vector3d ptEnd = JoinCutInstanceUtils::GetEndPoint(pInstance);
   ptStart.SetZ(ptPoint.GetZ());
   ptEnd.SetZ(ptPoint.GetZ());
   if (Vector3dUtils::Distance(ptStart, ptPoint) <= Vector3dUtils::Distance(ptEnd, ptPoint))
   {
      return JoinPosition::Start;
   }

   return JoinPosition::End;
}

std::pair<int, int> GbmpJoinUtils::GetInstanceJoinPositionIndex(const gcmp::IInstance* pAttachingInstance, const gcmp::IInstance* pAttachedInstance)
{
   std::pair<int, int> res(-1, -1);
   DBG_WARN_AND_RETURN_UNLESS(pAttachingInstance, res, L"无效pAttachingInstance",L"GDMPLab",L"2024-03-30");
   DBG_WARN_AND_RETURN_UNLESS(pAttachedInstance, res, L"无效pAttachedInstance",L"GDMPLab",L"2024-03-30");

   const IElementPositionPoints* pAttachedCtrlPtBehavior = pAttachedInstance->GetPositionPoints();
   const IElementPositionPoints* pAttachingCtrlPtBehavior = pAttachingInstance->GetPositionPoints();
   DBG_WARN_AND_RETURN_UNLESS(pAttachedCtrlPtBehavior && pAttachingCtrlPtBehavior, res, L"invalid parameter",L"GDMPLab",L"2024-03-30");

   Vector3d ptStart1 = pAttachingCtrlPtBehavior ? pAttachingCtrlPtBehavior->GetControlPoint(0) : Vector3d::Zero;
   Vector3d ptEnd1 = pAttachingCtrlPtBehavior ? pAttachingCtrlPtBehavior->GetControlPoint(1) : Vector3d::Zero;
   Vector3d ptStart2 = pAttachedCtrlPtBehavior ? pAttachedCtrlPtBehavior->GetControlPoint(0) : Vector3d::Zero;
   Vector3d ptEnd2 = pAttachedCtrlPtBehavior ? pAttachedCtrlPtBehavior->GetControlPoint(1) : Vector3d::Zero;
   double dDistPtStart1ToPtStart2 = Vector3dUtils::Distance(ptStart1, ptStart2);
   double dDistPtStart1ToPtEnd2 = Vector3dUtils::Distance(ptStart1, ptEnd2);
   double dDistPtEnd1ToPtStart2 = Vector3dUtils::Distance(ptEnd1, ptStart2);
   double dDistPtEnd1ToPtEnd2 = Vector3dUtils::Distance(ptEnd1, ptEnd2);
   std::map<double, std::pair<int, int>> distMaps;
   distMaps[dDistPtStart1ToPtStart2] = std::make_pair(0, 0);
   distMaps[dDistPtStart1ToPtEnd2] = std::make_pair(0, 1);
   distMaps[dDistPtEnd1ToPtStart2] = std::make_pair(1, 0);
   distMaps[dDistPtEnd1ToPtEnd2] = std::make_pair(1, 1);
   return  distMaps.begin()->second;
}

